package com.yonyou.wdt.job;

import cn.hutool.core.map.MapUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import com.yonyou.wdt.dao.JobLogDao;
import com.yonyou.wdt.dao.WarehouseOrgDao;
import com.yonyou.wdt.entity.OpenApiURLEnum;
import com.yonyou.wdt.entity.QueryDto;
import com.yonyou.wdt.job.config.BaseConfig;
import com.yonyou.wdt.model.JobLogModel;
import com.yonyou.wdt.model.WarehouseOrgModel;
import com.yonyou.wdt.qimenmodel.qimencloud.api.DefaultQimenCloudClient;
import com.yonyou.wdt.qimenmodel.qimencloud.api.scenehu3cgwt0tc.request.WdtStockoutOrderQueryTradeRequest;
import com.yonyou.wdt.qimenmodel.qimencloud.api.scenehu3cgwt0tc.response.WdtStockoutOrderQueryTradeResponse;
import com.yonyou.wdt.service.CommonService;
import com.yonyou.wdt.service.YonsuiteService;
import com.yonyou.wdt.utils.DateUtils;
import com.yonyou.wdt.utils.ReSubmitUtil;
import com.yonyou.wdt.utils.RedisUtils;
import com.yonyou.wdt.utils.WdtConfigProperties;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

@Component
public class WdtQmSaleOutToYsSaleOrder extends BaseConfig {


    private static final Logger logger = LoggerFactory.getLogger(WdtQmSaleOutToYsSaleOrder.class);
    private final WdtConfigProperties configProperties;
    @Resource
    private YonsuiteService yonsuiteService;
    @Resource
    public JobLogDao jobLogDao;
    @Resource
    public WarehouseOrgDao warehouseOrgDao;
    @Resource
    public CommonService commonService;

    @Autowired
    public WdtQmSaleOutToYsSaleOrder(WdtConfigProperties configProperties) {
        this.configProperties = configProperties;
    }

    @XxlJob("WdtQmSaleOutToYsSaleOrder")
    public ReturnT<String> wdtQmSaleOutToYsSaleOrder(String params) throws Exception {
        String param = XxlJobHelper.getJobParam();
        Map<String, Object> map = new HashMap<>();
        if (param != null && !"".equals(param)) {
            if (param.contains("&")) {
                List<String> timeRange = Arrays.asList(param.split("&"));
                if (timeRange.size() == 2) {
                    map.put("Start", timeRange.get(0));
                    map.put("End", timeRange.get(1));
                } else if (timeRange.size() == 3) {
                    map.put("Start", timeRange.get(0));
                    map.put("End", timeRange.get(1));
                    map.put("shop_no", timeRange.get(2));
                } else {
                    map.put("Start", timeRange.get(0));
                    map.put("End", timeRange.get(1));
                    map.put("shop_no", timeRange.get(2));
                    map.put("warehouse_no", timeRange.get(3));
                }
            } else {
                List<String> timeRange = Arrays.asList(param.split("\\|"));
                if (timeRange.size() == 2) {
                    map.put("Start", timeRange.get(0));
                    map.put("End", timeRange.get(1));
                } else {
                    map.put("src_tid", timeRange.get(0));
                }
            }
        } else {
            // 默认查询前一天的数据
            map.put("Start", DateUtils.getStartDate());
            map.put("End", DateUtils.getEndDate());
        }
        String dateStr = null;
        if (map.get("Start") != null && map.get("End") != null) {
            dateStr = map.get("Start").toString() + map.get("End").toString();
        }

        // 处理相关业务
        QueryDto dto = new QueryDto();
        dto.setTenantId(getYsTenantId());
        dto.setAppKey(getYsAppKey());
        dto.setAppSecret(getYsAppSecret());
        // 获取YS系统租户动态域名信息
        ReturnT<String> isReturn2 = getYsDynamicDomainName(dto);
        // 域名获取失败
        if (isReturn2 != null) return isReturn2;
        try {
            getMerchantList(dto);
            List<JSONObject> jsonObjectList = sendWdtByQm(map, dto);
            // jsonObjectList = new ArrayList<>();
            Integer successCount = 0;
            Integer failCount = 0;
            // jsonObjectList = new ArrayList<>();
            // 解析数据，组装YS请求参数
            // 子表拆分
            List<JSONObject> resobjects = new ArrayList<>();
            if (!jsonObjectList.isEmpty()) {
                resobjects = detaillSplit(jsonObjectList);
            }
            if (!resobjects.isEmpty()) {
                // 查询YS仓库档案列表
                HashMap<String, String> ckData = getCkData(dto, yonsuiteService);

                for (int i = 0; i < resobjects.size(); i++) {
                    JSONObject jsonObject = resobjects.get(i);
                    //for (JSONObject jsonObject : responseList) {
                    Map<String, Object> ysSaveParam = assembleYsParams(jsonObject, dto, ckData, param);
                    if (ysSaveParam == null) {
                        failCount++;
                        continue;
                    }
                    JSONObject response = yonsuiteService.saleOrderSave(ysSaveParam, dto);
                    if (null != response && "200".equals(response.getStr("code"))) {
                        successCount++;
                        logger.info("旺店通销售出库汇总保存YS销售订单成功");
                        InsertLogger(null, "1", "旺店通销售出库汇总保存YS销售订单" + response.getJSONObject("data").getStr("code") + "成功");
                    } else {
                        failCount++;
                        logger.error("旺店通销售出库汇总保存YS销售订单失败：{}", response.getOrDefault("message", ""));
                        InsertLogger(null, "0", "旺店通销售出库汇总保存YS销售订单接口失败" + response.getOrDefault("message", "").toString());
                    }
                    // 处理YS接口调用频率问题
                    // 调用YS接口保存数据
                    this.APICurrentLimiting(OpenApiURLEnum.SALES_ORDER_SAVE, 59);
                }
                logger.info("当前时间段：{} 需要同步到YS销售订单数据有：{}条", dateStr, resobjects.size());
            }
            Thread.sleep(1000);
            InsertLogger(null, "0", "当前时间段：" + dateStr + ",旺店通销售出库汇总一共" + resobjects.size() + "条,保存YS销售订单成功:" + successCount + "条，失败:" + failCount + "条。");

        } catch (Exception e) {
            logger.error("Error occurred", e);
            logger.error("旺店通销售出库汇总同步YS销售订单失败，{}", e.getMessage());
            InsertLogger(null, "0", "旺店通销售出库汇总error同步YS销售订单失败" + e);
            return ReturnT.FAIL;
        }
        logger.info("  --  旺店通销售出库汇总同步YS销售订单任务执行完成  --  ");
        return ReturnT.SUCCESS;
    }

    private List<JSONObject> detaillSplit(List<JSONObject> jsonObjectList) {
        ArrayList<JSONObject> jsonObjects = new ArrayList<>();
        for (JSONObject entries : jsonObjectList) {
            JSONArray jsonArray = entries.getJSONArray("details_list");
            if (jsonArray.size() > 400) {

                int pageCount = jsonArray.size() % 400 == 0 ? jsonArray.size() / 400 : (jsonArray.size() / 400) + 1;
                for (int i = 0; i < pageCount; i++) {
                    JSONObject entries1 = JSONUtil.parseObj(entries);
                    List<Object> detailList;
                    if (i == pageCount - 1) {
                        detailList = jsonArray.subList(i * 400, jsonArray.size());
                    } else {
                        detailList = jsonArray.subList(i * 400, (i + 1) * 400);
                    }
                    entries1.set("details_list", detailList);
                    jsonObjects.add(entries1);
                }
            } else {
                jsonObjects.add(entries);
            }
        }
        return jsonObjects;
    }

    /**
     * @return
     * @Author Huangwb
     * @Description 旺店通数据分组
     * @Date 10:21 2023/5/15
     * @Param
     **/
    private List<JSONObject> groupBy(List<JSONObject> responseList, String consignTime) {
        List<JSONObject> resultList = new ArrayList<>();
        try {

            Map<String, List<JSONObject>> createdDateMap = responseList.stream().collect(Collectors.groupingBy(json -> json.getStr("pay_time").substring(0, 10)));
            createdDateMap.forEach((payTime, createdValue) -> {
                Map<String, Map<String, Map<String, List<JSONObject>>>> collect = createdValue.stream().collect(Collectors.groupingBy(json -> json.getStr("shop_no"), Collectors.groupingBy(json -> json.getStr("warehouse_no"), Collectors.groupingBy(json -> json.getStr("trade_type")))));
                collect.forEach((shopNo, warehouseMap) -> {
                    warehouseMap.forEach((warehouseNo, warehouseItems) -> {
                        warehouseItems.forEach((tradeType, tradeTypeItems) -> {
                            //List<JSONObject> allItems = tradeTypeItems.stream().flatMap(element -> element.getJSONArray("details_list").stream()).map(o -> (JSONObject) o).collect(Collectors.toList());
                            List<JSONObject> allItems = new ArrayList<>();
                            tradeTypeItems.forEach(element -> {
                                List details = element.getJSONArray("details_list");
                                allItems.addAll(details);
                            });
                            //有组合装的
                            Map<String, Map<String, Map<String, List<JSONObject>>>> collect2 = allItems.stream().filter(obj -> StringUtils.isNotBlank(JSONUtil.parseObj(obj).getStr("suite_no"))).collect(Collectors.groupingBy(json -> json.getStr("goods_no"), Collectors.groupingBy(json -> json.getStr("suite_no"), Collectors.groupingBy(json -> json.getStr("src_tids")))));
                            //没有组合装
                            Map<String, List<JSONObject>> collect1 = allItems.stream().filter(obj -> StringUtils.isBlank(JSONUtil.parseObj(obj).getStr("suite_no"))).collect(Collectors.groupingBy(json -> json.getStr("goods_no")));

                            ArrayList<Object> itemsListResultList = new ArrayList<>();
                            collect1.forEach((sku_id, details) -> {
                                BigDecimal numsNew = BigDecimal.valueOf(0);
                                BigDecimal sumSaleNew = BigDecimal.valueOf(0.00);
                                Map<String, Object> theFirstItem = new HashMap<>();
                                theFirstItem = details.get(0);
                                for (int i = 0; i < details.size(); i++) {
                                    //获取每笔订单的数量和实付金额
                                    BigDecimal nums = BigDecimal.valueOf(Double.parseDouble(details.get(i).getStr("goods_count")));//数量
                                    numsNew = numsNew.add(nums);
                                }
                                theFirstItem.put("goods_count", numsNew);
                                itemsListResultList.add(theFirstItem);
                            });


                            for (String s : collect2.keySet()) {
                                Map<String, Map<String, List<JSONObject>>> stringMapMap = collect2.get(s);
                                for (String string : stringMapMap.keySet()) {
                                    Map<String, List<JSONObject>> stringListMap = stringMapMap.get(string);
                                    List<JSONObject> collect3 = stringListMap.entrySet().stream().map(entry -> {
                                        List<JSONObject> items = entry.getValue();
                                        BigDecimal qtyNew = items.stream().map(json -> json.getBigDecimal("goods_count")).reduce(BigDecimal.ZERO, BigDecimal::add);
                                        JSONObject theFirstItem = items.isEmpty() ? new JSONObject() : items.get(0);
                                        theFirstItem.put("goods_count", qtyNew);
                                        theFirstItem.put("src_tids", items.get(0).getStr("src_tids"));
                                        theFirstItem.put("suite_no", items.get(0).getStr("suite_no"));
                                        return theFirstItem;
                                    }).collect(Collectors.toList());
                                    itemsListResultList.addAll(collect3);
                                }
                            }
                            JSONObject resultJson = new JSONObject();
                            resultJson.put("shop_no", shopNo);
                            resultJson.put("warehouse_no", warehouseNo);
                            resultJson.put("modified", consignTime);
                            resultJson.put("pay_time", payTime);
                            resultJson.put("trade_type", tradeType);
                            resultJson.put("details_list", itemsListResultList);
                            resultList.add(resultJson);
                        });
                    });
                });
            });

        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultList;
    }

    /**
     * @return
     * @Author Huangwb
     * @Description 组装YS请求数据
     * @Date 14:34 2023/5/17
     * @Param
     **/
    private Map<String, Object> assembleYsParams(JSONObject jsonObject, QueryDto dto, HashMap<String, String> ckData, String param) throws Exception {
        Map<String, Object> data = new HashMap<>();
        Map<String, Object> body = new HashMap<>();
        // ==========主表============


        String warehouseNo = jsonObject.getStr("warehouse_no");


        WarehouseOrgModel warehouseOrgModel = warehouseOrgDao.queryOrgByWarehouse(warehouseNo);
        if (warehouseOrgModel == null) {
            InsertLogger(null, "0", "根据仓库编码：" + warehouseNo + "查询组织失败，请同步后重试");
            return null;
        }
        String orgId = warehouseOrgModel.getOrg();
        body.put("warehouse", warehouseNo); // 仓库id或编码

        String shopNo = jsonObject.getStr("shop_no");
        body.put("salesOrgId", orgId);  // 销售组织，传id或者code
        String tradeType = jsonObject.getStr("trade_type");
        if (tradeType.equals("1")) {
            body.put("transactionTypeId", "HY07");  // 交易类型，传id或者code - 销售出库
        } else if (tradeType.equals("2")) {
            body.put("transactionTypeId", "HY01");  // 交易类型，传id或者code - 销售出库
        } else if (tradeType.equals("3")) {
            body.put("transactionTypeId", "HY02");  // 交易类型，传id或者code - 销售出库
        } else if (tradeType.equals("4")) {
            body.put("transactionTypeId", "HY03");  // 交易类型，传id或者code - 销售出库
        } else if (tradeType.equals("5")) {
            body.put("transactionTypeId", "HY04");  // 交易类型，传id或者code - 销售出库
        } else if (tradeType.equals("6")) {
            body.put("transactionTypeId", "HY05");  // 交易类型，传id或者code - 销售出库
        } else if (tradeType.equals("8")) {
            body.put("transactionTypeId", "HY06");  // 交易类型，传id或者code - 销售出库
        } else if (tradeType.equals("7")) {
            body.put("transactionTypeId", "HY06");  // 交易类型，传id或者code - 销售出库
        }

	/*	SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
		String vouchdate = format.format(jsonObject.getLong("bill_date"));*/
        body.put("vouchdate", jsonObject.getStr("modified")); // 单据日期
        body.put("agentId", shopNo);  // 客户，传id或者code
        body.put("saleDepartmentId", shopNo);  // 销售部门，传id或者code
        body.put("corpContact", "00000104");  // 销售业务员，传id或者code
        body.put("settlementOrgId", orgId);  // 开票组织，传id或者code
        body.put("orderPrices!currency", "CNY");  // 币种，传id或者code
        body.put("orderPrices!exchRate", 1);  // 汇率
        body.put("orderPrices!exchangeRateType", "01");  // 汇率类型，传id或者code
        body.put("orderPrices!natCurrency", "CNY");  // 本币，传id或者code
        body.put("orderPrices!taxInclusive", true);  // 单价含税
        body.put("invoiceAgentId", shopNo);  // 开票客户，传id或者code
        body.put("_status", "Insert");  // 操作标识
        HashMap<String, Object> defHashMap = new HashMap<>();
        defHashMap.put("E_01", jsonObject.getStr("pay_time"));
        defHashMap.put("E_06", ckData.get(warehouseNo));
        body.put("orderDefineCharacter", defHashMap);  // 表头自定义项特征组

        // 获取Redis中客户档案信息
        JSONObject custPrJson = (JSONObject) RedisUtils.get(dto.getTenantId() + ":cust:" + shopNo);
        if (custPrJson == null) {
            // 保存同步错误日志，未找到对应物料档案信息
            logger.error("存在未同步YS系统客户数据：{}，请同步后重试", shopNo);
            InsertLogger(null, "0", "存在未同步YS系统客户数据：" + shopNo + "，请同步后重试");
            return null;
        }

        JSONArray items = jsonObject.getJSONArray("details_list");
        BigDecimal payMoney = BigDecimal.ZERO;
        // ==========子表============
        JSONArray details = new JSONArray();
        for (Object element : items) {
            JSONObject item = (JSONObject) element;
            // 获取物料编码
            String product = item.getStr("goods_no");
            String suiteNo = item.getStr("suite_no");

            // 获取Redis中物料档案信息
            JSONObject redisPrJson = (JSONObject) RedisUtils.get(dto.getTenantId() + ":product:" + product);
            if (redisPrJson == null) {
                // 保存同步错误日志，未找到对应物料档案信息
                commonService.proToRedis(product, dto);
                redisPrJson = (JSONObject) RedisUtils.get(dto.getTenantId() + ":product:" + product);
                if (redisPrJson == null) {
                    logger.error("存在未同步YS系统物料数据：{}，请同步后重试", product);
                    InsertLogger(null, "0", "存在未同步YS系统物料数据：" + product + "，请同步后重试,店铺：" + shopNo + "仓库：" + warehouseNo);
                    return null;
                }
            }
            HashMap<String, Object> saleOutDetail = new HashMap<>();
            //BigDecimal saleAmount = BigDecimal.ZERO;
            BigDecimal outTaxrate;
            BigDecimal unitPriceIncludingTax = BigDecimal.ZERO;
            BigDecimal taxAmount = BigDecimal.ZERO;
            BigDecimal noTaxSaleAmount = BigDecimal.ZERO;
            BigDecimal taxFreeUnitPrice = BigDecimal.ZERO;
            BigDecimal nums = item.getBigDecimal("goods_count");

            JSONObject entries = commonService.priceListQuery(orgId, body.get("vouchdate").toString(), dto);
            BigDecimal price = new BigDecimal(0.01).setScale(2, BigDecimal.ROUND_HALF_UP);
            if (entries != null && "200".equals(entries.getStr("code"))) {
                JSONArray priceData = entries.getJSONArray("data");
                JSONObject pricingRecordJson = new JSONObject();
                String customerLevelId = custPrJson.getStr("customerLevelId");
                if (!priceData.isEmpty() && StringUtils.isNotBlank(customerLevelId)) {
                    for (Object datum : priceData) {
                        JSONObject datumJson = (JSONObject) datum;

                        if (datumJson.getStr("productId_code").equals(product) && customerLevelId.equals(datumJson.getStr("dimension_agentLevelId"))) {
                            pricingRecordJson = datumJson;
                            break;
                        }
                    }
                    /*if (pricingRecordJson.isEmpty()) {
                        logger.error("查询价格表失败：{}", entries.getStr("message"));
                        InsertLogger(null, "0", "查询价格表失败：" + entries.getStr("message"));
                        return null;
                    }*/
                    // 存在调价单
                    if (pricingRecordJson.getBigDecimal("adjustGradients_price") != null) {
                        // 调价单维护了价格，价格取调价单金额
                        // 获取成本价
                        price = pricingRecordJson.getBigDecimal("adjustGradients_price");
                    }
                }
            } else {
                /*logger.error("查询价格表失败：{}", entries.getStr("message"));
                InsertLogger(body.get("code").toString(), "0", "查询价格表失败：" + entries.getStr("message"));
                return null;*/
            }
            //BigDecimal price = BigDecimal.ONE;
            BigDecimal saleAmount = nums.multiply(price).setScale(2, RoundingMode.HALF_UP);
            // String taxId = "VATR1";
            String taxId = "NL";
            if (saleAmount != null) {
                // 金额
                // saleAmount = item.getBigDecimal("sum_sale");
                // 税率
                outTaxrate = redisPrJson.containsKey("outTaxrate_name") ? redisPrJson.getBigDecimal("outTaxrate_name") : BigDecimal.ZERO;
                taxId = redisPrJson.getStr("productDetail_outTaxrate") != null ? redisPrJson.getStr("productDetail_outTaxrate") : "TE";

                outTaxrate = new BigDecimal(0);
                // 含税单价
                unitPriceIncludingTax = saleAmount.divide(nums, 4, RoundingMode.HALF_UP);
                // 税额
                if (!"0".equals(outTaxrate.toString())) {
                    taxAmount = saleAmount.divide(outTaxrate.divide(new BigDecimal(100)).add(new BigDecimal(1)), 4, RoundingMode.HALF_UP).multiply(outTaxrate.divide(new BigDecimal(100), 4, RoundingMode.HALF_UP)).setScale(2, RoundingMode.HALF_UP);
                    // taxAmount = saleAmount.multiply(outTaxrate.divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_UP));
                }
                // 无税金额
                noTaxSaleAmount = saleAmount.subtract(taxAmount);
                // 无税单价
                taxFreeUnitPrice = noTaxSaleAmount.divide(BigDecimal.valueOf(Double.parseDouble(String.valueOf(nums))), 4, RoundingMode.HALF_UP);
            }
            payMoney = payMoney.add(saleAmount);
            String unit = redisPrJson.getStr("unitCode");
            //String unit = "无";
            saleOutDetail.put("productId", product); // 物料id或编码
            saleOutDetail.put("oriSum", saleAmount);  // 含税金额 BigDecimal
            saleOutDetail.put("saleCost", saleAmount);  // 报价含税金额 BigDecimal
            saleOutDetail.put("oriTaxUnitPrice", unitPriceIncludingTax);  // 含税成交价 BigDecimal
            saleOutDetail.put("salePrice", unitPriceIncludingTax);  // 含税报价  BigDecimal
            saleOutDetail.put("orderDetailPrices!oriUnitPrice", taxFreeUnitPrice);  // 无税成交价 BigDecimal
            saleOutDetail.put("noTaxSalePrice", taxFreeUnitPrice);  // 无税报价 BigDecimal
            saleOutDetail.put("orderDetailPrices!natSum", saleAmount);  // 本币含税金额
            saleOutDetail.put("orderDetailPrices!natMoney", noTaxSaleAmount);  // 本币无税金额
            saleOutDetail.put("orderDetailPrices!natTax", taxAmount);  // 本币税额 BigDecimal
            saleOutDetail.put("orderDetailPrices!oriTax", taxAmount);  // 税额 BigDecimal
            saleOutDetail.put("orderDetailPrices!oriMoney", noTaxSaleAmount);  // 无税金额 BigDecimal
            saleOutDetail.put("orderDetailPrices!natTaxUnitPrice", unitPriceIncludingTax);  // 本币含税单价 BigDecimal
            saleOutDetail.put("orderDetailPrices!natUnitPrice", taxFreeUnitPrice);  // 本币无税单价
            saleOutDetail.put("masterUnitId", unit);  // 主计量单位，传id或者code
            saleOutDetail.put("invExchRate", 1);  // 销售换算率 BigDecimal
            saleOutDetail.put("unitExchangeTypePrice", 0);  // 浮动（销售）int
            saleOutDetail.put("iProductAuxUnitId", unit);  // 销售单位，传id或者code
            saleOutDetail.put("invPriceExchRate", 1);  // 计价换算率
            saleOutDetail.put("priceQty", nums);  // 计价数量 BigDecimal
            saleOutDetail.put("stockOrgId", orgId);  // 库存组织id或库存组织code
            saleOutDetail.put("stockId", warehouseNo);  // 仓库
            saleOutDetail.put("iProductUnitId", unit);  // 计价单位，传id或者code
            saleOutDetail.put("orderProductType", "SALE");  // 商品售卖类型
            saleOutDetail.put("subQty", nums);  // 销售数量 BigDecimal
            saleOutDetail.put("consignTime", jsonObject.getStr("modified"));  // 计划发货日期,格式为:yyyy-MM-dd HH:mm:ss
            saleOutDetail.put("taxId", taxId);  // 税目税率，传id或者code
            saleOutDetail.put("qty", nums);  // 数量 BigDecimal
            saleOutDetail.put("settlementOrgId", orgId);  // 开票组织，传id或者code
            saleOutDetail.put("unitExchangeType", 0);  // 浮动（计价） int
            saleOutDetail.put("_status", "Insert");  // 操作标识
            saleOutDetail.put("isBatchManage", true);  // 是否批次管理, true:是、false:否、    示例: false
            saleOutDetail.put("batchNo", "旺店通");  // 批次号
            //调用销售保存接口时，子表为PTO母件商品行需要加个字段 "virtualProductAttribute":16
            /*if (item.containsKey("isSuite") && item.getBool("isSuite")) {
                saleOutDetail.put("productId", product); // 物料id或编码
                saleOutDetail.put("virtualProductAttribute", "16");
            }*/
            if (StringUtils.isNotBlank(suiteNo)) {
                HashMap<String, Object> detailDefMap = new HashMap<>();
                Object o = RedisUtils.get(dto.getTenantId() + ":bom:" + suiteNo);
                if (o == null) {
                    setBomToRedis(suiteNo, dto);
                }
                o = RedisUtils.get(dto.getTenantId() + ":bom:" + suiteNo);
                if (o == null) {
                    InsertLogger(null, "0", "存在未同步YS系统物料清单数据：" + suiteNo + "，请同步后重试");
                    return null;
                }
                List<JSONObject> list = JSONUtil.toList(o.toString(), JSONObject.class);
                BigDecimal newQty = BigDecimal.ZERO;
                for (JSONObject object : list) {
                    JSONObject entries1 = JSONUtil.parseObj(object);
                    if (product.equals(entries1.getStr("bomComponent_productCode"))) {
                        newQty = nums.divide(entries1.getBigDecimal("bomComponent_stockQuantity"), 4, BigDecimal.ROUND_HALF_UP);
                        break;
                    }
                }
                detailDefMap.put("E_05", newQty);
                detailDefMap.put("E_03", item.getStr("src_tids"));
                detailDefMap.put("E_02", suiteNo);
                detailDefMap.put("C_02", redisPrJson.getBigDecimal("weight"));
                saleOutDetail.put("orderDetailDefineCharacter", detailDefMap);
            }
            details.add(saleOutDetail);
        }
        body.put("payMoney", payMoney);  // 合计含税金额
        body.put("totalMoney", payMoney);  // 总金额

        body.put("orderDetails", details);
        // 幂等
        if (param.contains("&")) {
            body.put("resubmitCheckKey", UUID.randomUUID().toString().replace("-", ""));
        } else {
            body.put("resubmitCheckKey", "test20250108");
            ReSubmitUtil.resubmitCheckKey(body);
        }
        data.put("data", body);
        return data;
    }


    public static HashMap<String, String> getCkData(QueryDto dto, YonsuiteService yonsuiteService) throws Exception {
        // 1、仓库列表查询，查询出所有仓库，将id与code拼装成一个map集合，进行比对判断
        HashMap<String, Object> queryMap = new HashMap<>();  // 仓库档案列表查询请求参数Map
        ArrayList<JSONObject> warehouseList = new ArrayList<>();  // 仓库档案列表查询返回值
        int pageIndex = 1;
        while (true) {
            queryMap.put("pageIndex", pageIndex);
            queryMap.put("pageSize", 100);
            JSONObject wareJsonList = yonsuiteService.warehouseListQuery(queryMap, dto);
            if (wareJsonList.getStr("code").equals("200")) {
                if (null != wareJsonList.getJSONObject("data") && null != wareJsonList.getJSONObject("data").getJSONArray("recordList")) {
                    JSONArray purJSONArray = wareJsonList.getJSONObject("data").getJSONArray("recordList");
                    for (Object warehouse : purJSONArray) {
                        JSONObject warehouseJson = JSONUtil.parseObj(warehouse);
                        warehouseList.add(warehouseJson);
                    }
                }
            }
            if (wareJsonList.getJSONObject("data").getInt("pageCount") <= pageIndex && wareJsonList.getJSONObject("data").getJSONArray("recordList").size() < 100) {
                break;
            }
            pageIndex++;
        }
        logger.info("YS系统仓库档案查询完成共：{}个仓库", warehouseList.size());
        HashMap<String, String> warehouseMap = new HashMap<>();
        for (JSONObject warehouseJson : warehouseList) {
            warehouseMap.put(warehouseJson.getStr("code"), warehouseJson.getStr("name"));
        }
        return warehouseMap;
    }

    public static void main(String[] args) {
        BigDecimal price = new BigDecimal(0.01).setScale(2, BigDecimal.ROUND_HALF_UP);
        System.out.println(price);
    }

    private void setBomToRedis(String product, QueryDto dto) throws Exception {
        Map<String, Object> wlParam = new HashMap<>();
        wlParam.put("productCode", product);

        wlParam.put("pageIndex", 1);
        wlParam.put("pageSize", 100);
        boolean isNext = true;
        List<Map<String, List<JSONObject>>> list = new ArrayList();
        int error = 0;
        int pageIndex = 1;
        while (true) {
            wlParam.put("pageIndex", pageIndex);
            JSONObject allocationRes = yonsuiteService.ysBomListQuery(wlParam, dto);
            if (allocationRes.getStr("code").equals("200")) {
                if (null != allocationRes.getJSONObject("data") && null != allocationRes.getJSONObject("data").getJSONArray("recordList")) {
                    JSONArray purJSONArray = allocationRes.getJSONObject("data").getJSONArray("recordList");
                    List<JSONObject> reqList = JSONUtil.toList(purJSONArray, JSONObject.class);
                    Map<String, List<JSONObject>> collectMap = reqList.stream().collect(Collectors.groupingBy(json -> json.getStr("code")));
                    for (String s : collectMap.keySet()) {
                        HashMap<String, List<JSONObject>> stringListHashMap = new HashMap<>();
                        stringListHashMap.put(s, collectMap.get(s));
                        list.add(stringListHashMap);
                    }
                }
            }
            // 调用YS接口保存数据
            this.APICurrentLimiting(OpenApiURLEnum.BOM_LIST_QUERY, 59);
            if (allocationRes.getJSONObject("data").getInt("pageCount") == 0) {
                break;
            }
            if (allocationRes.getJSONObject("data").getInt("pageCount") <= pageIndex) {
                break;
            }
            pageIndex++;
        }
        if (list.size() > 0) {
            for (Map<String, List<JSONObject>> wlObject : list) {
                Set<String> strings = wlObject.keySet();
                for (String string : strings) {
                    RedisUtils.set(dto.getTenantId() + ":bom:" + string, wlObject.get(string), 60 * 60 * 24 * 30);
                }
            }
            logger.info("租户：{} YS系统物料档案同步Redis完成，共同步物料档案：{}条", dto.getTenantId(), list.size());
            InsertLogger(MapUtil.getStr(wlParam, ("productCode")), "1", "租户：{" + dto.getTenantId() + "} YS系统物料档案同步Redis完成，共同步物料档案：{" + list.size() + "}条");
        }
    }

    /**
     * @Author Huangwb
     * @Description 查询YS系统租户动态域名信息
     * @Date 2023/10/30 15:45
     **/
    public ReturnT<String> getYsDynamicDomainName(QueryDto ysQueryDto) {
        try {
            String tenantId = ysQueryDto.getTenantId();  // 租户ID
            if (RedisUtils.get(tenantId + ":DynamicDomainName") == null) {
                // 根据租户ID查询动态域名
                JSONObject dynamicDomainName = yonsuiteService.getDynamicDomainName(null, tenantId);
                if (null != dynamicDomainName && !dynamicDomainName.isEmpty()) {
                    // 将动态域名存入Redis
                    RedisUtils.set(tenantId + ":DynamicDomainName", dynamicDomainName, 86400 * 30);
                } else {
                    logger.error("查询租户【{}】动态域名失败，请重试", tenantId);
                    // insertXxlJobLog(null, "0", "租户：【" + tenantId + "】获取动态域名失败，请稍后重试", jobClassType);
                    InsertLogger(null, "0", "获取动态域名失败");
                    return new ReturnT<>(ReturnT.FAIL_CODE, "查询租户【" + tenantId + "】动态域名失败，请重试");
                }
            }
            // 获取Redis中指定租户动态域名
            JSONObject dynamicDomainNameRedis = (JSONObject) RedisUtils.get(tenantId + ":DynamicDomainName");
            ysQueryDto.setGatewayUrl(dynamicDomainNameRedis.getStr("gatewayUrl"));
            ysQueryDto.setTokenUrl(dynamicDomainNameRedis.getStr("tokenUrl"));
            return null;
        } catch (Exception e) {
            return new ReturnT<>(ReturnT.FAIL_CODE, "获取动态域名失败：" + e.getMessage());
        }
    }

    /**
     * @return
     * @Author Huangwb
     * @Description 插入数据库日志信息
     * @Date 10:30 2023/9/14
     * @Param
     **/
    private void InsertLogger(String code, String oneL, String mags) {  // 单据编号、是否成功、详细信息
        try {
            JobLogModel jobLogDTO = new JobLogModel();
            jobLogDTO.setJobClass("HYZM009");
            jobLogDTO.setJobCode(code);
            jobLogDTO.setJobTime(new Date());
            jobLogDTO.setJobResult(oneL);
            jobLogDTO.setJobResultMessage(mags);
            jobLogDTO.setJobLogUser("dxroot");
            jobLogDao.insertJobLog(jobLogDTO);
        } catch (Exception e) {
            logger.error("插入日志错误：" + e.getMessage());
        }
    }


    private List<JSONObject> sendWdtByQm(Map<String, Object> map, QueryDto dto) {
        List<JSONObject> resList = new ArrayList<>();
        DefaultQimenCloudClient client = new DefaultQimenCloudClient(configProperties.getQmServerUrl(), configProperties.getQmAppKey(), configProperties.getQmAppSecret(), "json");
        Integer realityPageNo = 0;
        map.put("page_no", realityPageNo.toString());
        map.put("page_size", "100");
        // map.put("shop_no", "20240514-5");
        //map.put("warehouse_no", "1");
        //map.put("status", 95);
        boolean hasNext = true;
        //总页数
        Integer totalPage = 0;
        //总条数
        ArrayList<JSONObject> mergeBeforeList = new ArrayList<>();
        Integer total_count = 0;
        String consign_time = null;
        try {
            while (hasNext) {
                map.put("page_no", realityPageNo.toString());
                WdtStockoutOrderQueryTradeRequest req = this.setModel(map, configProperties.getQmTargetAppKey(), configProperties.getSid());
                WdtStockoutOrderQueryTradeResponse res = null;
                try {
                    res = client.execute(req);
                } catch (com.yonyou.wdt.qimenmodel.taobao.api.ApiException e) {
                    throw new RuntimeException(e);
                }
                JSONObject saleOutJson = JSONUtil.parseObj(res.getBody()).getJSONObject("response");
                if ("0".equals(saleOutJson.getStr("errorcode"))) {
                    //判断分页
                    if (realityPageNo == 0) {
                        total_count = saleOutJson.getInt("total_count", 0);
                        totalPage = total_count % 100 == 0 ? total_count / 100 : total_count / 100 + 1;
                    }
                    //每页订单列表
                    JSONArray orderArray = saleOutJson.getJSONArray("stockout_list");
                    if (orderArray.size() > 0) {
                        //resList.addAll(JSONUtil.toList(orderArray,JSONObject.class));

                        List<JSONObject> list = JSONUtil.toList(orderArray, JSONObject.class);
                        //list = list.stream().filter(o -> "95".equals(o.getStr("status")) || "110".equals(o.getStr("status"))).collect(Collectors.toList());
                        mergeBeforeList.addAll(list);
                        //ArrayList<JSONObject> reqJsonObjects = getBeforeJsonObjects(list);
                        getDetailByCode(list, dto);
                        resList.addAll(list);
                        if (StringUtils.isBlank(consign_time)) {
                            consign_time = resList.get(0).getStr("consign_time");
                        }
                        resList = groupBy(resList, consign_time);
                    }
                    //判断分页
                    if (realityPageNo == 0) {
                        total_count = saleOutJson.getInt("total_count", 0);
                        totalPage = total_count % 100 == 0 ? total_count / 100 : total_count / 100 + 1;
                    }
                    if (totalPage >= 60) {
                        if (totalPage == 60) {
                            if (realityPageNo == 25) {
                                Thread.sleep(1500);
                            }
                        } else {
                            Thread.sleep(1000);
                        }
                    }
                    if (totalPage > realityPageNo + 1) {
                        realityPageNo += 1;
                    } else {
                        hasNext = false;
                    }
                } else {
                    InsertLogger(null, "0", "旺店通销售出库接口查询失败" + saleOutJson.getStr("message"));
                    break;
                }
            }
        } catch (Exception e) {
            logger.error("Error occurred", e);
            logger.error("查询旺店通退货入库单失败：【{}】", e.getMessage());
        }
        InsertLogger(null, "0", "旺店通销售出库汇总前:" + mergeBeforeList.size() + "条,汇总后:" + resList.size() + "条");
        return resList;
    }

    private List<JSONObject> getDetailByCode(List<JSONObject> list, QueryDto dto) {
        for (JSONObject entries : list) {
            String custName = entries.getStr("fenxiao_nick");
            if (StringUtils.isNotBlank(custName)) {
                Object o = RedisUtils.get("cust:" + dto.getTenantId() + ":" + custName);
                if (o == null) {
                    // InsertLogger(null, "0", "旺店通销售出库根据分销商名称查询ys客户档案编码失败，分销商名称:" + custName);
                } else {
                    entries.set("shop_no", o);
                }
            }
            JSONArray jsonArray = entries.getJSONArray("details_list");
            List<JSONObject> detailList = JSONUtil.toList(jsonArray, JSONObject.class);
            for (JSONObject detail : detailList) {
                detail.set("src_tids", entries.getStr("src_tids"));
            }
            if (entries.getStr("pay_time").substring(0, 10).equals("0000-00-00")) {
                System.out.println(entries);
                entries.set("pay_time", entries.getStr("created"));
            }
        }
        return list;
    }

    private void getMerchantList(QueryDto dto) {
        int productPageNo = 1;
        int pageSizeNum = 500;
        try {
            Map<String, Object> map = new HashMap<>();
            map.put("pageIndex", productPageNo);
            map.put("pageSize", pageSizeNum);
            map.put("customerClassCode", "HY020");
            JSONObject customerResult = yonsuiteService.merchantListQuery(map, dto);
            if (customerResult.getStr("code").equals("200")) {
                List data = customerResult.getJSONArray("data");
                for (Object datum : data) {
                    JSONObject entries = JSONUtil.parseObj(datum);
                    String customerName = entries.getJSONObject("name").getStr("simplifiedName");
                    // 将已经存在的客户数据保存至Redis
                    RedisUtils.set("cust:" + dto.getTenantId() + ":" + customerName, entries.getStr("code"), 60 * 60 * 24 * 30);
                }
            }
            this.APICurrentLimiting(OpenApiURLEnum.MERCHANT_LIST_QUERY, 60);
        } catch (Exception e) {
            logger.error("Error occurred", e);
            logger.error("YS客户档案列表查询失败：{}", e.getMessage());
        }

    }

    public WdtStockoutOrderQueryTradeRequest setModel(Map param, String targetAppKey, String sid) {
        WdtStockoutOrderQueryTradeRequest req = new WdtStockoutOrderQueryTradeRequest();
        //旺店通的奇门appkey
        req.setTargetAppKey(targetAppKey);
        //旺店通erp的卖家账号
        req.setSid(sid);
        String startTime = MapUtil.getStr(param, "Start");
        if (StringUtils.isNotBlank(startTime)) {
            req.setStartTime(startTime);
        }
        String endTime = MapUtil.getStr(param, "End");
        if (StringUtils.isNotBlank(endTime)) {
            req.setEndTime(endTime);
        }
        Long status = MapUtil.getLong(param, "status");
        if (status != null) {
            req.setStatus(status);
        }
        String srcOrderNo = MapUtil.getStr(param, "src_order_no");
        if (StringUtils.isNotBlank(srcOrderNo)) {
            req.setSrcOrderNo(srcOrderNo);
        }
        String srcTid = MapUtil.getStr(param, "src_tid");
        if (StringUtils.isNotBlank(srcTid)) {
            req.setSrcTid(srcTid);
        }
        String stockoutNo = MapUtil.getStr(param, "stockout_no");
        if (StringUtils.isNotBlank(stockoutNo)) {
            req.setStockoutNo(stockoutNo);
        }
        if (param.containsKey("page_no")) {
            req.setPageNo(MapUtil.getLong(param, "page_no"));
        }
        if (param.containsKey("page_size")) {
            req.setPageSize(MapUtil.getLong(param, "page_size"));
        }
        Integer isByModified = MapUtil.getInt(param, "is_by_modified");
        if (isByModified != null) {
            req.setIsByModified(isByModified);
        }
        String shop_no = MapUtil.getStr(param, "shop_no");
        if (StringUtils.isNotBlank(shop_no)) {
            req.setShopNo(shop_no);
        }
        if (param.containsKey("shop_nos")) {
            req.setShopNos(MapUtil.getStr(param, "shop_nos"));
        }
        String warehouseNo = MapUtil.getStr(param, "warehouse_no");
        if (StringUtils.isNotBlank(warehouseNo)) {
            req.setWarehouseNo(warehouseNo);
        }
        Integer isNoPosition = MapUtil.getInt(param, "is_no_position");
        if (isNoPosition != null) {
            req.setIsNoPosition(isNoPosition);
        }
        return req;
    }
}
